home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / uupc11ys.zip / UUCP / UUX.C < prev    next >
C/C++ Source or Header  |  1993-04-10  |  41KB  |  1,124 lines

  1. /*
  2.       Program:    uux.c              27 August 1991
  3.       Author:     Mitch Mitchell
  4.       Email:      mitch@harlie.lonestar.org
  5.  
  6.       Much of this code is shamelessly taken from extant code in
  7.       UUPC/Extended.
  8.  
  9.       Usage:      uux [ options ] command-string
  10.  
  11.                Where [ options ] are:
  12.  
  13.      -aname    Use name as the user identification replacing the initiator
  14.                user-id.  (Notification will be returned to the user.)
  15.  
  16.      -b        Return whatever standard input was provided to the uux command
  17.                if the exit status is non-zero.
  18.  
  19.      -c        Do not copy local file to the spool directory for transfer to
  20.                the remote machine (default).
  21.  
  22.      -C        Force the copy of local files to the spool directory for
  23.                transfer.
  24.  
  25.      -e        Remote system should use sh to execute commands.
  26.  
  27.      -E        Remote system should use exec to execute commands.
  28.  
  29.      -ggrade   Grade is a single letter/number; lower ASCII sequence
  30.                characters will cause the job to be transmitted earlier during
  31.                a particular conversation.
  32.  
  33.      -j        Output the jobid ASCII string on the standard output which is
  34.                the job identification.  This job identification can be used by
  35.                uustat to obtain the status or terminate a job.
  36.  
  37.      -n        Do not notify the user if the command fails.
  38.  
  39.      -p        The standard input to uux is made the standard input to the
  40.                command-string.
  41.  
  42.      -r        Do not start the file transfer, just queue the job.
  43.                (Currently uux does not attempt to start the transfer
  44.                 regardless of the presense of this option).
  45.  
  46.      -sfile    Report status of the transfer in file.
  47.  
  48.      -xdebug_level
  49.                Produce debugging output on the standard output.  The
  50.                debug_level is a number between 0 and ??; higher numbers give
  51.                more detailed information.
  52.  
  53.      -z        Send success notification to the user.
  54.  
  55.  
  56.       The command-string is made up of one or more arguments that
  57.       look like a normal command line, except that the command and
  58.       filenames may be prefixed by system-name!.  A null
  59.       system-name is interpreted as the local system.
  60.  
  61. */
  62.  
  63. /*--------------------------------------------------------------------*/
  64. /*         System include files                                       */
  65. /*--------------------------------------------------------------------*/
  66.  
  67. #include <stdio.h>
  68. #include <io.h>
  69. #include <string.h>
  70. #include <time.h>
  71. #include <stdlib.h>
  72. #include <fcntl.h>
  73. #include <sys/types.h>
  74. #include <sys/stat.h>
  75.  
  76. /*--------------------------------------------------------------------*/
  77. /*         Local include files                                        */
  78. /*--------------------------------------------------------------------*/
  79.  
  80. #include  "lib.h"
  81. #include  "hlib.h"
  82. #include  "getopt.h"
  83. #include  "getseq.h"
  84. #include  "expath.h"
  85. #include  "import.h"
  86. #include  "pushpop.h"
  87. #include  "security.h"
  88. #include  "hostable.h"
  89. #include  "timestmp.h"
  90.  
  91. /*--------------------------------------------------------------------*/
  92. /*        Define current file name for panic() and printerr()         */
  93. /*--------------------------------------------------------------------*/
  94.  
  95. currentfile();
  96.  
  97. /*--------------------------------------------------------------------*/
  98. /*                          Global variables                          */
  99. /*--------------------------------------------------------------------*/
  100.  
  101. typedef enum {
  102.           FLG_USE_USERID,
  103.           FLG_OUTPUT_JOBID,
  104.           FLG_READ_STDIN,
  105.           FLG_QUEUE_ONLY,
  106.           FLG_NOTIFY_SUCCESS,
  107.           FLG_NONOTIFY_FAIL,
  108.           FLG_COPY_SPOOL,
  109.           FLG_RETURN_STDIN,
  110.           FLG_STATUS_FILE,
  111.           FLG_USE_EXEC,
  112.           FLG_MAXIMUM
  113.        } UuxFlags;
  114.  
  115. typedef enum {
  116.       DATA_FILE   = 0,        /* Normal data file passed argument    */
  117.       INPUT_FILE  = 1,        /* Redirected stdin file               */
  118.       OUTPUT_FILE = 2         /* Redirected stdout file              */
  119.       } FileType;
  120.  
  121. static boolean flags[FLG_MAXIMUM] = {
  122.                                         FALSE,
  123.                                         FALSE,
  124.                                         FALSE,
  125.                                         FALSE,
  126.                                         FALSE,
  127.                                         FALSE,
  128.                                         FALSE,
  129.                                         FALSE,
  130.                                         FALSE,
  131.                                         FALSE
  132.                                     };
  133. static char* st_out = NULL;
  134. static char* user_id = NULL;
  135. static char  grade = 'Z';          /* Default grade of service */
  136.  
  137. static char  job_id[15];
  138.  
  139. static char* spool_fmt = SPOOLFMT;
  140. static char* dataf_fmt = DATAFFMT;
  141.  
  142. static char* send_cmd  = "S %s %s %s - %s 0666\n";
  143.  
  144. /*--------------------------------------------------------------------*/
  145. /*                        Internal prototypes                         */
  146. /*--------------------------------------------------------------------*/
  147.  
  148. void main(int  argc, char  **argv);
  149. static void usage( void );
  150. static char *SwapSlash(char *p);
  151. static boolean cp(char *from, char *to);
  152. static boolean split_path(char *path,
  153.                           char *system,
  154.                           char *file,
  155.                           boolean expand,
  156.                           char *default_sys);
  157. static boolean CopyData( const char *input, const char *output);
  158. static boolean remove_parens(char *string);
  159. static boolean do_uuxqt(char *job_name, char *src_syst, char *src_file, char *dest_syst, char *dest_file);
  160. static boolean do_copy(char *src_syst, char *src_file, char *dest_syst, char *dest_file);
  161. static boolean do_remote(int optind, int argc, char **argv);
  162. static void preamble(FILE* stream);
  163. static char subseq( void );
  164.  
  165. /*--------------------------------------------------------------------*/
  166. /*    u s a g e                                                       */
  167. /*                                                                    */
  168. /*    Report flags used by program                                    */
  169. /*--------------------------------------------------------------------*/
  170.  
  171. static void usage()
  172. {
  173.       fprintf(stderr, "Usage: uux\t[-c|-C] [-e|-E] [-b] [-gGRADE] "
  174.                       "[-p] [-j] [-n] [-r] [-sFILE]\\\n"
  175.                       "\t\t[-aNAME] [-z] [-] [-xDEBUG_LEVEL] "
  176.                       "command-string\n");
  177. }
  178.  
  179.  
  180. /*--------------------------------------------------------------------*/
  181. /*    s w a p s l a s h                                               */
  182. /*                                                                    */
  183. /*    Change backslash in a directory path to forward slash           */
  184. /*--------------------------------------------------------------------*/
  185.  
  186. static char *SwapSlash(char *p)
  187. {
  188.      char *q = p;
  189.  
  190.      while (*q) {
  191.         if (*q ==  '\\')
  192.            *q = '/';
  193.         q++;
  194.      }
  195.      return p;
  196. };
  197.  
  198. /*--------------------------------------------------------------------*/
  199. /*    c p                                                             */
  200. /*                                                                    */
  201. /*    Copy Local Files                                                */
  202. /*--------------------------------------------------------------------*/
  203.  
  204. static boolean cp(char *from, char *to)
  205. {
  206.       int  fd_from, fd_to;
  207.       int  nr;
  208.       int  nw = -1;
  209.       char buf[BUFSIZ];            /* faster if we alloc a big buffer */
  210.  
  211.       /* This would be even faster if we determined that both files
  212.          were on the same device, dos >= 3.0, and used the dos move
  213.          function */
  214.  
  215.       if ((fd_from = open(from, O_RDONLY | O_BINARY)) == -1)
  216.          return FALSE;        /* failed */
  217.  
  218.       /* what if the to is a directory? */
  219.       /* possible with local source & dest uucp */
  220.  
  221.       if ((fd_to = open(to, O_CREAT | O_BINARY | O_WRONLY, S_IWRITE | S_IREAD)) == -1) {
  222.          close(fd_from);
  223.          return FALSE;        /* failed */
  224.          /* NOTE - this assumes all the required directories exist!  */
  225.       }
  226.  
  227.       while  ((nr = read(fd_from, buf, sizeof buf)) > 0 &&
  228.          (nw = write(fd_to, buf, nr)) == nr)
  229.          ;
  230.  
  231.       close(fd_to);
  232.       close(fd_from);
  233.  
  234.       if (nr != 0 || nw == -1)
  235.          return FALSE;        /* failed in copy */
  236.       return TRUE;
  237. }
  238.  
  239.  
  240. /*--------------------------------------------------------------------*/
  241. /*    C o p y D a t a                                                 */
  242. /*                                                                    */
  243. /*    Copy data into its final resting spot                           */
  244. /*--------------------------------------------------------------------*/
  245.  
  246. static boolean CopyData( const char *input, const char *output)
  247. {
  248.    FILE    *datain;
  249.    FILE    *dataout;
  250.    char     buf[BUFSIZ];
  251.    boolean  status = TRUE;
  252.    int      len;
  253.  
  254.    if ( (dataout = FOPEN(output, "w", BINARY_MODE)) == NULL ) {
  255.       printerr(output);
  256.       printmsg(0,"uux: Cannot open spool file \"%s\" for output",
  257.                output);
  258.       return FALSE;
  259.    }
  260.  
  261. /*--------------------------------------------------------------------*/
  262. /*                      Verify the input opened                       */
  263. /*--------------------------------------------------------------------*/
  264.  
  265.    if (input == NULL)
  266.    {
  267.       datain = stdin;
  268.       setmode(fileno(datain), O_BINARY);   /* Don't die on control-Z, etc */
  269.    }
  270.    else
  271.       datain = FOPEN(input, "r", BINARY_MODE);
  272.  
  273.    if (datain == NULL) {
  274.       printerr(input);
  275.       printmsg(0,"Unable to open input file \"%s\"",
  276.                (input == NULL ? "stdin" : input));
  277.       fclose(dataout);
  278.       return FALSE;
  279.    } /* datain */
  280.  
  281. /*--------------------------------------------------------------------*/
  282. /*                       Loop to copy the data                        */
  283. /*--------------------------------------------------------------------*/
  284.  
  285.    while ( (len = fread( buf, 1, BUFSIZ, datain)) != 0)
  286.    {
  287.       if (fwrite( buf, 1, len, dataout ) != len)     /* I/O error?               */
  288.       {
  289.          printerr("dataout");
  290.          printmsg(0,"I/O error on \"%s\"", output);
  291.          fclose(dataout);
  292.          return FALSE;
  293.       } /* if */
  294.    } /* while */
  295.  
  296. /*--------------------------------------------------------------------*/
  297. /*                      Close up shop and return                      */
  298. /*--------------------------------------------------------------------*/
  299.  
  300.    if (ferror(datain))        /* Clean end of file on input?          */
  301.    {
  302.       printerr(input);
  303.       clearerr(datain);
  304.       status = FALSE;
  305.    }
  306.  
  307.    if (input != NULL)
  308.        fclose(datain);
  309.  
  310.    fclose(dataout);
  311.    return status;
  312.  
  313. } /* CopyData */
  314.  
  315. /*--------------------------------------------------------------------*/
  316. /*    r e m o v e _ p a r e n s                                       */
  317. /*                                                                    */
  318. /*--------------------------------------------------------------------*/
  319.  
  320. static boolean remove_parens(char *string)
  321. {
  322.       int len = strlen(string);
  323.  
  324.       if ((string[0] != '(') || (string[len - 1] != ')'))
  325.           return FALSE;
  326.  
  327.       strcpy(string, &string[1]);
  328.       string[len - 2] = '\0';
  329.       return TRUE;                 /* and we're done */
  330. }
  331.  
  332. /*--------------------------------------------------------------------*/
  333. /*    s p l i t _ p a t h                                             */
  334. /*--------------------------------------------------------------------*/
  335.  
  336. static boolean split_path(char *path,
  337.                           char *sysname,
  338.                           char *file,
  339.                           boolean expand,
  340.                           char *default_sys )
  341. {
  342.       char *p_left;
  343.       char *p_right;
  344.       char *p = path;
  345.  
  346.       *sysname = *file = '\0';    /* init to nothing */
  347.  
  348. /*--------------------------------------------------------------------*/
  349. /*                if path is wildcarded then error                    */
  350. /*--------------------------------------------------------------------*/
  351.  
  352.    if (strcspn(path, "*?[") < strlen(path))
  353.    {
  354.       printmsg(0,"uux - Wildcards not allowed in operand: %s",p );
  355.       return FALSE;
  356.    }
  357.  
  358. /*--------------------------------------------------------------------*/
  359. /*                   Find the first and last bangs                    */
  360. /*--------------------------------------------------------------------*/
  361.  
  362.    p_left = strchr(p, '!');         /* look for the first bang    */
  363.    p_right = strrchr(p, '!');       /* look for the last bang     */
  364.  
  365. /*--------------------------------------------------------------------*/
  366. /*   If no bangs, then the file is on the remote system.  We hope.    */
  367. /*--------------------------------------------------------------------*/
  368.  
  369.    if ( p_left == NULL )
  370.    {
  371.       strcpy( file, p);       /* Entire string is file name          */
  372.  
  373.       strcpy( sysname, default_sys );   /* Use default system name   */
  374.  
  375.       if ( equal(sysname, E_nodename ) &&
  376.            expand &&
  377.            (expand_path(file, NULL, E_homedir, NULL) == NULL))
  378.          return FALSE;     /* expand_path will delivery any needed
  379.                                  nasty-gram to user                  */
  380.    } /* if ( p_left == NULL ) */
  381.  
  382. /*--------------------------------------------------------------------*/
  383. /*    If the first bang is the first character, it's a local file     */
  384. /*--------------------------------------------------------------------*/
  385.  
  386.       if (p_left == p)                 /* First character in path?   */
  387.       {                                /* Yes --> not a remote path  */
  388.  
  389.          if ( p_left != p_right )      /* More bangs?                */
  390.          {
  391.             printmsg(0,"uux - Invalid syntax for local file: %s", p );
  392.             return FALSE;              /* Yes --> I don't grok this  */
  393.          }
  394.  
  395.          strcpy(file, p+1);            /* Just return filename       */
  396.  
  397.          if ( expand && (expand_path(file, NULL, E_homedir, NULL) == NULL))
  398.             return FALSE;     /* expand_path will delivery any needed
  399.                                  nasty-gram to user                  */
  400.          strcpy(sysname, E_nodename);
  401.          return TRUE;
  402.       } /* p_left == p */
  403.  
  404. /*--------------------------------------------------------------------*/
  405. /*             It's not a local file, continue processing             */
  406. /*--------------------------------------------------------------------*/
  407.  
  408.       strcpy(file, p_right + 1);      /* and thats our filename */
  409.  
  410.       strncpy(sysname, p, p_left - p); /* and we have a system thats not us */
  411.       sysname[p_left - p] = '\0';
  412.  
  413. /*--------------------------------------------------------------------*/
  414. /*              Now see if there is an intermediate path              */
  415. /*--------------------------------------------------------------------*/
  416.  
  417.       if (p_left != p_right)
  418.       {
  419.           char c = *p_right;
  420.           *p_right = '\0';    /* Terminate the system name           */
  421.           printmsg(0,"uux - Intermediate system %s not supported", p_left+1);
  422.           *p_right = c;       /* Restore original string             */
  423.           return FALSE;
  424.       } /* if (p_left != p_right) */
  425.  
  426. #if 0
  427.       if (expand && (strcspn(file, "~") >= strlen(file)) )
  428.           if (expand_path(file, NULL, E_homedir, NULL) == NULL)
  429.              return FALSE;
  430. #endif
  431.  
  432.       return TRUE;                     /* and we're done */
  433. } /* split_path */
  434.  
  435. /*--------------------------------------------------------------------*/
  436. /*    d o _ u u x q t                                                 */
  437. /*                                                                    */
  438. /*    Generate a UUXQT command file for local system                  */
  439. /*--------------------------------------------------------------------*/
  440.  
  441. static boolean do_uuxqt(char *job_name,
  442.                         char *src_syst,
  443.                         char *src_file,
  444.                         char *dest_syst,
  445.                         char *dest_file)
  446. {
  447.    long seqno = 0;
  448.    char *seq  = NULL;
  449.    FILE *stream;              /* For writing out data                 */
  450.  
  451.    char msfile[FILENAME_MAX]; /* MS-DOS format name of files          */
  452.    char msname[22];           /* MS-DOS format w/o path name          */
  453.    char ixfile[15];           /* eXecute file for local system,
  454.                                  UNIX format name for local system    */
  455.  
  456. /*--------------------------------------------------------------------*/
  457. /*          Create the UNIX format of the file names we need          */
  458. /*--------------------------------------------------------------------*/
  459.  
  460.    seqno = getseq();
  461.    seq = JobNumber( seqno );
  462.  
  463.    sprintf(ixfile, spool_fmt, 'X', E_nodename, grade , seq);
  464.  
  465. /*--------------------------------------------------------------------*/
  466. /*                     create local X (xqt) file                      */
  467. /*--------------------------------------------------------------------*/
  468.  
  469.    importpath( msname, ixfile, E_nodename);
  470.    mkfilename( msfile, E_spooldir, msname);
  471.  
  472.    if ( (stream = FOPEN(msfile, "w", BINARY_MODE)) == NULL ) {
  473.       printerr(msfile);
  474.       printmsg(0, "uux: cannot open X file %s", msfile);
  475.       return FALSE;
  476.    } /* if */
  477.  
  478.    fprintf(stream, "# third party request, job id\n" );
  479.    fprintf(stream, "J %s\n",               job_name );
  480.    fprintf(stream, "F %s/%s/%s %s\n",      E_spooldir, src_syst, dest_file,
  481.                                           src_file );
  482.    fprintf(stream, "C uucp -C %s %s!%s\n", src_file, dest_syst, dest_file );
  483.    fclose (stream);
  484.  
  485.    return TRUE;
  486.  
  487. } /* do_uuxqt */
  488.  
  489. /*--------------------------------------------------------------------*/
  490. /*    d o _ c o p y                                                   */
  491. /*                                                                    */
  492. /*    At this point only one of the systems can be remote and only    */
  493. /*    1 hop away.  All the rest have been filtered out                */
  494. /*--------------------------------------------------------------------*/
  495.  
  496. static boolean do_copy(char *src_syst,
  497.                        char *src_file,
  498.                        char *dest_syst,
  499.                        char *dest_file)
  500. {
  501.       char    tmfile[25];               /* Unix style name for c file */
  502.       char    idfile[25];       /* Unix style name for data file copy */
  503.       char    work[66];             /* temp area for filename hacking */
  504.       char    icfilename[66];               /* our hacked c file path */
  505.       char    idfilename[66];               /* our hacked d file path */
  506.  
  507.       struct  stat    statbuf;
  508.  
  509.       long    int     sequence;
  510.       char    *remote_syst;    /* Non-local system in copy            */
  511.       char    *sequence_s;
  512.       FILE        *cfile;
  513.  
  514.       sequence = getseq();
  515.       sequence_s = JobNumber( sequence );
  516.  
  517.       remote_syst =  equal(src_syst, E_nodename) ? dest_syst : src_syst;
  518.  
  519.       sprintf(tmfile, spool_fmt, 'C', remote_syst, grade, sequence_s);
  520.       importpath(work, tmfile, remote_syst);
  521.       mkfilename(icfilename, E_spooldir, work);
  522.  
  523.       if (!equal(src_syst, E_nodename))
  524.       {
  525.          if (expand_path(dest_file, NULL, E_homedir, NULL) == NULL)
  526.             return FALSE;
  527.  
  528.          SwapSlash(src_file);
  529.  
  530.          printmsg(1, "uux - from \"%s\" - control = %s", src_syst,
  531.                   tmfile);
  532.          if ((cfile = FOPEN(icfilename, "a",TEXT_MODE)) == NULL)  {
  533.             printerr( icfilename );
  534.             printmsg(0, "uux: cannot append to %s\n", icfilename);
  535.             return FALSE;
  536.          }
  537.  
  538.          fprintf(cfile, "R %s %s %s -c D.0 0666", src_file, dest_file,
  539.                   E_mailbox);
  540.  
  541.          if (flags[FLG_USE_USERID])
  542.              fprintf(cfile, " %s\n", user_id);
  543.          else
  544.              fprintf(cfile, " %s\n", E_mailbox);
  545.  
  546.  
  547.          fclose(cfile);
  548.          return TRUE;
  549.       }
  550.       else if (!equal(dest_syst, E_nodename))  {
  551.  
  552.          printmsg(1,"uux - spool %s - execute %s",
  553.                   flags[FLG_COPY_SPOOL] ? "on" : "off",
  554.                   flags[FLG_QUEUE_ONLY] ? "do" : "don't");
  555.          printmsg(1,"     - dest m/c = %s  sequence = %ld  control = %s",
  556.                   dest_syst, sequence, tmfile);
  557.  
  558.          if (expand_path(src_file, NULL, E_homedir, NULL) == NULL)
  559.             return FALSE;
  560.  
  561.          SwapSlash(dest_file);
  562.  
  563.          if (stat(src_file, &statbuf) != 0)  {
  564.             printerr( src_file );
  565.             return FALSE;
  566.          }
  567.  
  568.          if (statbuf.st_mode & S_IFDIR)  {
  569.             printf("uux - directory name \"%s\" illegal\n",
  570.                     src_file );
  571.             return FALSE;
  572.          }
  573.  
  574.          if (flags[FLG_COPY_SPOOL]) {
  575.             sprintf(idfile , dataf_fmt, 'D', E_nodename, sequence_s,
  576.                               subseq());
  577.             importpath(work, idfile, remote_syst);
  578.             mkfilename(idfilename, E_spooldir, work);
  579.  
  580.             /* Do we need a MKDIR here for the system? */
  581.  
  582.             if (!cp(src_file, idfilename))  {
  583.                printmsg(0, "copy \"%s\" to \"%s\" failed",
  584.                   src_file, idfilename);           /* copy data */
  585.                return FALSE;
  586.             }
  587.          }
  588.          else
  589.             strcpy(idfile, "D.0");
  590.  
  591.          if ((cfile = FOPEN(icfilename, "a",TEXT_MODE)) == NULL)
  592.          {
  593.             printerr( icfilename );
  594.             printf("uux: cannot append to %s\n", icfilename);
  595.             return FALSE;
  596.          } /* if ((cfile = FOPEN(icfilename, "a",TEXT_MODE)) == NULL) */
  597.  
  598.          fprintf(cfile, "S %s %s %s -%s %s 0666", src_file, dest_file,
  599.                   E_mailbox, flags[FLG_COPY_SPOOL] ? "c" : " ", idfile);
  600.  
  601.          if (flags[FLG_USE_USERID])
  602.              fprintf(cfile, " %s\n", user_id);
  603.          else
  604.              fprintf(cfile, " %s\n", E_mailbox);
  605.  
  606.          fclose(cfile);
  607.  
  608.          return TRUE;
  609.       }
  610.       else {
  611.          if (expand_path(src_file, NULL, E_homedir, NULL) == NULL)
  612.             return FALSE;
  613.  
  614.          if (expand_path(dest_file, NULL, E_homedir, NULL) == NULL)
  615.             return FALSE;
  616.  
  617.          if (strcmp(src_file, dest_file) == 0)
  618.          {
  619.             printmsg(0, "%s %s - same file; can't copy\n",
  620.                   src_file, dest_file);
  621.             return FALSE;
  622.          } /* if (strcmp(src_file, dest_file) == 0) */
  623.  
  624.          return(cp(src_file, dest_file));
  625.       } /* else */
  626. } /* do_copy */
  627.  
  628. /*--------------------------------------------------------------------*/
  629. /*    p r e a m b l e                                                 */
  630. /*                                                                    */
  631. /*    write the execute file preamble based on the global flags       */
  632. /*--------------------------------------------------------------------*/
  633.  
  634. static void preamble(FILE* stream)
  635. {
  636.  
  637.      fprintf(stream, "U %s %s\n", E_mailbox, E_nodename);
  638.  
  639.      if (flags[FLG_RETURN_STDIN]) {
  640.          fprintf(stream, "# return input on abnormal exit\n");
  641.          fprintf(stream, "B\n");
  642.      }
  643.  
  644.      if (flags[FLG_NOTIFY_SUCCESS]) {
  645.          fprintf(stream, "# return status on success\n");
  646.          fprintf(stream, "n\n");
  647.      }
  648.  
  649.      if (flags[FLG_NONOTIFY_FAIL]) {
  650.          fprintf(stream, "# don't return status on failure\n");
  651.          fprintf(stream, "N\n");
  652.      } else {
  653.          fprintf(stream, "# return status on failure\n");
  654.          fprintf(stream, "Z\n");
  655.      }
  656.  
  657.      if (flags[FLG_USE_EXEC]) {
  658.          fprintf(stream, "# use exec to execute\n");
  659.          fprintf(stream, "E\n");
  660.      } else {
  661.          fprintf(stream, "# use sh execute\n");
  662.          fprintf(stream, "e\n");
  663.      }
  664.  
  665.      if (flags[FLG_STATUS_FILE]) {
  666.         fprintf(stream, "M %s\n", st_out );
  667.      }
  668.  
  669.      if (flags[FLG_USE_USERID]) {
  670.          fprintf(stream, "# return address for status or input return\n");
  671.          fprintf(stream, "R %s\n", user_id );
  672.      }
  673.  
  674.      fprintf(stream, "# job id for status reporting\n");
  675.      fprintf(stream, "J %s\n", job_id );
  676.      return;
  677. } /* preamble */
  678.  
  679. /*--------------------------------------------------------------------*/
  680. /*    d o _ r e m o t e                                               */
  681. /*                                                                    */
  682. /*   gather data files to ship to execution system and build X file   */
  683. /*--------------------------------------------------------------------*/
  684.  
  685. static boolean do_remote(int optind, int argc, char **argv)
  686. {
  687.    FILE    *stream;           /* For writing out data              */
  688.    char    *sequence_s;
  689.  
  690.    boolean s_remote;
  691.    boolean d_remote;
  692.    boolean i_remote = FALSE;
  693.    boolean o_remote = FALSE;
  694.  
  695.    long    sequence;
  696.  
  697.    char    src_system[100];
  698.    char    dest_system[100];
  699.    char    src_file[FILENAME_MAX];
  700.    char    dest_file[FILENAME_MAX];
  701.  
  702.    char    command[BUFSIZ];
  703.  
  704.    char    msfile[FILENAME_MAX];    /* MS-DOS format name of files */
  705.    char    msname[22];              /* MS-DOS format w/o path name */
  706.  
  707.    char    tmfile[15];        /* Call file, UNIX format name       */
  708.    char    lxfile[15];        /* eXecute file for remote system,
  709.                                  UNIX format name for local system */
  710.    char    rxfile[15];        /* Remote system UNIX name of eXecute
  711.                                  file                              */
  712.    char    lifile[15];        /* Data file, UNIX format name       */
  713.    char    rifile[15];        /* Data file name on remote system,
  714.                                  UNIX format                       */
  715.    char* jobid_fmt = &spool_fmt[3];
  716.  
  717.  
  718. /*--------------------------------------------------------------------*/
  719. /*    Get the remote system and command to execute on that system     */
  720. /*--------------------------------------------------------------------*/
  721.  
  722.    if (!split_path(argv[optind++], dest_system, command, FALSE, E_nodename))
  723.    {
  724.       printmsg(0, "uux - illegal syntax %s", argv[--optind]);
  725.       return FALSE;
  726.    }
  727.  
  728.    d_remote = equal(dest_system, E_nodename) ? FALSE : TRUE ;
  729.  
  730. /*--------------------------------------------------------------------*/
  731. /*        OK - we have a destination system - do we know him?         */
  732. /*--------------------------------------------------------------------*/
  733.  
  734.    if ((d_remote) && (checkreal(dest_system) == BADHOST))
  735.    {
  736.       printmsg(0, "uux - bad system: %s", dest_system);
  737.       return FALSE;
  738.    }
  739.  
  740.    printmsg(9,"xsys -> %s", dest_system);
  741.    printmsg(9, "system \"%s\", rest \"%s\"", dest_system, command);
  742.  
  743.    sequence = getseq();
  744.    sequence_s = JobNumber( sequence );
  745.  
  746.    sprintf(job_id, jobid_fmt, dest_system, grade, sequence_s);
  747.  
  748. /*--------------------------------------------------------------------*/
  749. /*                     create remote X (xqt) file                     */
  750. /*--------------------------------------------------------------------*/
  751.  
  752.       sprintf(rxfile, dataf_fmt, 'X', E_nodename, sequence_s, subseq());
  753.       sprintf(lxfile, dataf_fmt, d_remote ? 'D' : 'X', E_nodename,
  754.               sequence_s, subseq());
  755.  
  756.       importpath( msname, lxfile, dest_system);
  757.       mkfilename( msfile, E_spooldir, msname);
  758.  
  759.       if ( (stream = FOPEN(msfile, "w", BINARY_MODE)) == NULL ) {
  760.          printerr(msfile);
  761.          printmsg(0, "uux: cannot open X file %s", msfile);
  762.          return FALSE;
  763.       } /* if */
  764.  
  765.       preamble(stream);
  766.  
  767. /*--------------------------------------------------------------------*/
  768. /*           Process options for the remote command                   */
  769. /*--------------------------------------------------------------------*/
  770.  
  771.       for (; optind < argc; optind++)
  772.       {
  773.  
  774.          FileType f_remote = DATA_FILE;
  775.  
  776.          if (*argv[optind] == '-')
  777.          {
  778.              strcat(command," ");
  779.              strcat(command,argv[optind]);
  780.              printmsg(9, "prm -> %s", argv[optind]);
  781.              continue;
  782.          }
  783.          else if (equal(argv[optind], "<"))
  784.          {
  785.              if (i_remote) {
  786.                  printmsg(0, "uux - multiple input files specified");
  787.                  return FALSE;
  788.              }
  789.              else
  790.                  i_remote = TRUE;
  791.  
  792.              f_remote = INPUT_FILE;
  793.              printmsg(9, "prm -> %s", argv[optind]);
  794.              optind++;
  795.  
  796.          }
  797.          else if (equal(argv[optind], ">"))
  798.          {
  799.              if (o_remote) {
  800.                  printmsg(0, "uux - multiple output files specified");
  801.                  return FALSE;
  802.              } else
  803.                  o_remote = TRUE;
  804.              f_remote = OUTPUT_FILE;
  805.              printmsg(9, "prm -> %s", argv[optind]);
  806.              optind++;
  807.          } else if (equal(argv[optind], "|")) {
  808.              strcat(command," ");
  809.              strcat(command,argv[optind]);
  810.              printmsg(9, "prm -> %s", argv[optind]);
  811.              continue;
  812.          } else if (remove_parens(argv[optind])) {
  813.              strcat(command," ");
  814.              strcat(command,argv[optind]);
  815.              printmsg(9, "prm -> %s", argv[optind]);
  816.              continue;
  817.          }
  818.  
  819.          printmsg(9, "prm -> %s", argv[optind]);
  820.  
  821.          if (!split_path(argv[optind], src_system, src_file, TRUE, dest_system))
  822.          {
  823.             printmsg(0, "uux - illegal syntax %s", argv[optind]);
  824.             return FALSE;
  825.          } /* if (!split_path()) */
  826.  
  827.          s_remote = equal(src_system, E_nodename) ? FALSE : TRUE ;
  828.  
  829. /*--------------------------------------------------------------------*/
  830. /*                   Do we know the source system?                    */
  831. /*--------------------------------------------------------------------*/
  832.  
  833.          if ((s_remote) && (checkreal(src_system) == BADHOST))
  834.          {
  835.             printmsg(0, "uux - bad system %s\n", src_system);
  836.             return FALSE;
  837.          } /* if ((s_remote) && (checkreal(src_system) == BADHOST)) */
  838.  
  839.         if (f_remote == DATA_FILE)
  840.         {
  841.            strcat(command, " ");
  842.            strcat(command, src_file);
  843.         } /* if (f_remote == DATA_FILE) */
  844.  
  845.         if (f_remote == OUTPUT_FILE)
  846.         {
  847.            fprintf(stream, "O %s %s\n", src_file,
  848.                    (equal(src_system, dest_system) ? " " : src_system) );
  849.            continue;
  850.         } /* if (f_remote == OUTPUT_FILE) */
  851.         else if (f_remote == INPUT_FILE)
  852.            fprintf(stream, "I %s\n", src_file);
  853.  
  854. /*--------------------------------------------------------------------*/
  855. /*    if both source & dest are not the same we must copy src_file    */
  856. /*--------------------------------------------------------------------*/
  857.  
  858.          if ( !equal(src_system, dest_system) )
  859.          {
  860.  
  861.             sprintf(dest_file, dataf_fmt, 'D', src_system, sequence_s,
  862.                     subseq());
  863.  
  864.             fprintf(stream, "F %s %s\n", dest_file, src_file );
  865.  
  866. /*--------------------------------------------------------------------*/
  867. /*      if source is remote and dest is local copy source to local    */
  868. /*      if source is local and dest is remote copy source to remote   */
  869. /*--------------------------------------------------------------------*/
  870.  
  871.             if ((s_remote && !d_remote) || (!s_remote && d_remote))
  872.             {
  873.                if (!do_copy(src_system, src_file, dest_system, dest_file))
  874.                    return FALSE;
  875.             } /* if ((s_remote && !d_remote) || (!s_remote && d_remote)) */
  876.  
  877. /*--------------------------------------------------------------------*/
  878. /*      if both source & dest are on remote nodes we need uuxqt       */
  879. /*--------------------------------------------------------------------*/
  880.  
  881.             else if (s_remote && d_remote)
  882.             {
  883.                if (!do_uuxqt(job_id, src_system, src_file, dest_system, dest_file))
  884.                    return FALSE;
  885.                if (!do_copy(src_system, src_file, E_nodename, dest_file))
  886.                    return FALSE;
  887.             } /* else if (s_remote && d_remote) */
  888.  
  889.             continue;
  890.          } /* if ( !equal(src_system, dest_system) ) */
  891.  
  892.          printmsg(4, "system \"%s\", rest \"%s\"", src_system, src_file);
  893.  
  894.       } /* for (; optind < argc; optind++) */
  895.  
  896. /*--------------------------------------------------------------------*/
  897. /*  Create the data file if any to send to the remote system          */
  898. /*--------------------------------------------------------------------*/
  899.  
  900.       if (flags[FLG_READ_STDIN]) {
  901.           if (i_remote) {
  902.               printmsg(0, "uux - multiple input files specified");
  903.               return FALSE;
  904.           }
  905.  
  906.           sprintf(rifile, dataf_fmt, 'D', E_nodename, sequence_s,
  907.                   subseq());
  908.           sprintf(lifile, dataf_fmt, 'D', E_nodename, sequence_s,
  909.                   subseq());
  910.  
  911.           importpath(msname, lifile, dest_system);
  912.           mkfilename(msfile, E_spooldir, msname);
  913.  
  914.           if (!CopyData( NULL, msfile )) {
  915.               remove( msfile );
  916.               return FALSE;
  917.           }
  918.  
  919.           fprintf(stream, "F %s\n", rifile);
  920.           fprintf(stream, "I %s\n", rifile);
  921.       }
  922.  
  923. /*--------------------------------------------------------------------*/
  924. /*           here finish writing parameters to the X file             */
  925. /*--------------------------------------------------------------------*/
  926.  
  927.       printmsg(4, "command \"%s\"", command);
  928.  
  929.  
  930.       fprintf(stream, "C %s\n", command);
  931.       fclose(stream);
  932.  
  933. /*--------------------------------------------------------------------*/
  934. /*                     create local C (call) file                     */
  935. /*--------------------------------------------------------------------*/
  936.  
  937.      if (d_remote) {
  938.           sprintf(tmfile, spool_fmt, 'C', dest_system,  grade, sequence_s);
  939.           importpath( msname, tmfile, dest_system);
  940.           mkfilename( msfile, E_spooldir, msname);
  941.  
  942.           if ( (stream = FOPEN(msfile, "a",TEXT_MODE)) == NULL) {
  943.              printerr( msname );
  944.              printmsg(0, "uux: cannot write/append to C file %s", msfile);
  945.              return FALSE;
  946.           }
  947.  
  948.           fprintf(stream, send_cmd, lxfile, rxfile, E_mailbox, lxfile);
  949.  
  950.           if (flags[FLG_READ_STDIN])
  951.               fprintf(stream, send_cmd, lifile, rifile, E_mailbox, lifile);
  952.  
  953.           fclose(stream);
  954.      }
  955.      return TRUE;
  956. } /* do_remote */
  957.  
  958. /*--------------------------------------------------------------------*/
  959. /*    m a i n                                                         */
  960. /*                                                                    */
  961. /*    main program                                                    */
  962. /*--------------------------------------------------------------------*/
  963.  
  964. void main(int  argc, char  **argv)
  965. {
  966.    int         c;
  967.    extern char *optarg;
  968.    extern int   optind;
  969.  
  970. /*--------------------------------------------------------------------*/
  971. /*     Report our version number and date/time compiled               */
  972. /*--------------------------------------------------------------------*/
  973.  
  974.    debuglevel = 0;
  975.    banner( argv );
  976.  
  977. #if defined(__CORE__)
  978.    copywrong = strdup(copyright);
  979.    checkref(copywrong);
  980. #endif
  981.  
  982.    if (!configure( B_UUCP ))
  983.       exit(1);   /* system configuration failed */
  984.  
  985. /*--------------------------------------------------------------------*/
  986. /*                   Switch to the spool directory                    */
  987. /*--------------------------------------------------------------------*/
  988.  
  989.    tzset();                      /* Set up time zone information  */
  990.  
  991.    PushDir( E_spooldir );
  992.    atexit( PopDir );
  993.  
  994.    user_id = E_mailbox;
  995.  
  996. /*--------------------------------------------------------------------*/
  997. /*        Process our arguments                                       */
  998. /*--------------------------------------------------------------------*/
  999.  
  1000. /*--------------------------------------------------------------------*
  1001.  *
  1002.  *   -aname    Use name as the user identification replacing the initiator
  1003.  *   -b        Return whatever standard input was provided to the uux command
  1004.  *   -c        Do not copy local file to the spool directory for transfer to
  1005.  *   -C        Force the copy of local files to the spool directory for
  1006.  *   -E        run job using exec
  1007.  *   -e        run job using sh
  1008.  *   -ggrade   Grade is a single letter number; lower ASCII sequence
  1009.  *   -j        Output the jobid ASCII string on the standard output which is
  1010.  *   -n        Do not notify the user if the command fails.
  1011.  *   -p        Same as -:  The standard input to uux is made the standard
  1012.  *   -r        Do not start the file transfer, just queue the job.
  1013.  *   -sfile    Report status of the transfer in file.
  1014.  *   -xdebug_level
  1015.  *   -z        Send success notification to the user.
  1016.  *
  1017. /*--------------------------------------------------------------------*/
  1018.  
  1019.    while ((c = getopt(argc, argv, "-a:bcCEejg:nprs:x:z")) !=  EOF)
  1020.       switch(c) {
  1021.       case '-':
  1022.          flags[FLG_READ_STDIN] = TRUE;
  1023.          break;
  1024.       case 'a':
  1025.          flags[FLG_USE_USERID] = TRUE;
  1026.          user_id = optarg;
  1027.          break;
  1028.       case 'b':
  1029.          flags[FLG_RETURN_STDIN] = TRUE;
  1030.          break;
  1031.       case 'c':               /* don't spool */
  1032.          flags[FLG_COPY_SPOOL] = FALSE;
  1033.          break;
  1034.       case 'C':               /* force spool */
  1035.          flags[FLG_COPY_SPOOL] = TRUE;
  1036.          break;
  1037.       case 'E':               /* use exec to execute */
  1038.          flags[FLG_USE_EXEC] = TRUE;
  1039.          break;
  1040.       case 'e':               /* use sh to execute */
  1041.          flags[FLG_USE_EXEC] = FALSE;
  1042.          break;
  1043.       case 'j':               /* output job id to stdout */
  1044.          flags[FLG_OUTPUT_JOBID] = TRUE;
  1045.          break;
  1046.       case 'n':               /* do not notify user if command fails */
  1047.          flags[FLG_NONOTIFY_FAIL] = TRUE;
  1048.          break;
  1049.       case 'p':
  1050.          flags[FLG_READ_STDIN] = TRUE;
  1051.          break;
  1052.       case 'r':               /* queue job only */
  1053.          flags[FLG_QUEUE_ONLY] = TRUE;
  1054.          break;
  1055.       case 'z':
  1056.          flags[FLG_NOTIFY_SUCCESS] = TRUE;
  1057.          break;
  1058.       case 'g':               /* set grade of transfer */
  1059.          grade = *optarg;
  1060.          break;
  1061.       case 's':               /* report status of transfer to file */
  1062.          flags[FLG_STATUS_FILE] = TRUE;
  1063.          st_out = optarg;
  1064.          break;
  1065.       case 'x':
  1066.          debuglevel = atoi( optarg );
  1067.          break;
  1068.       case '?':
  1069.          usage();
  1070.          exit(1);
  1071.          break;
  1072.       default:
  1073.          printmsg(0, "uux - bad argument from getopt \"%c\"", c);
  1074.          exit(1);
  1075.          break;
  1076.    }
  1077.  
  1078.    if (argc - optind < 1)     /* Verify we have at least a command   */
  1079.    {
  1080.       printmsg(0,"uux - no command to execute!");
  1081.       usage();
  1082.       exit(1);
  1083.    }
  1084.  
  1085.    if (!do_remote(optind, argc, argv))
  1086.    {
  1087.       printmsg(0, "uux command failed");
  1088.       exit(1);
  1089.    };
  1090.  
  1091.    if (flags[FLG_OUTPUT_JOBID])
  1092.        printf("%s\n", job_id);
  1093.  
  1094.    exit(0);
  1095. } /* main */
  1096.  
  1097. /*--------------------------------------------------------------------*/
  1098. /*    s u b s e q                                                    */
  1099. /*                                                                    */
  1100. /*    Generate a valid sub-sequence number                            */
  1101. /*--------------------------------------------------------------------*/
  1102.  
  1103. static char subseq( void )
  1104. {
  1105.    static char next = '0' - 1;
  1106.  
  1107.    switch( next )
  1108.    {
  1109.       case '9':
  1110.          next = 'A';
  1111.          break;
  1112.  
  1113.       case 'Z':
  1114.          next = 'a';
  1115.          break;
  1116.  
  1117.       default:
  1118.          next += 1;
  1119.    } /* switch */
  1120.  
  1121.    return next;
  1122.  
  1123. } /* subseq */
  1124.